package com.mayihr.table.demo2;

import java.util.HashMap;
import java.util.Map;


import com.mayihr.table.data.User;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.util.Callback;
import javafx.util.StringConverter;
import javafx.util.converter.DefaultStringConverter;

public class TableViewPane2 extends StackPane {

	private final BorderPane borderPane = new BorderPane();
	private final Map<String, Boolean> map = new HashMap<String, Boolean>();
	private final TableView<User> table = new TableView<>();
	private final ObservableList<User> dataList = FXCollections.observableArrayList();
	private final HBox hb = new HBox();
	private final HBox top = new HBox();
	private final Button showSelectButton = new Button("显示选中的");
	private final Button showDataButton = new Button("显示数据");

	public TableViewPane2() {
		initComponent();
		iniEvent();
		iniData();
	}

	@SuppressWarnings("unchecked")
	private void initComponent() {
		this.getChildren().add(borderPane);

		table.setEditable(true);
		// DefaultStringConverter dsc = new DefaultStringConverter();

		TableColumn<User, Boolean> selectColumn = new TableColumn<>("选择");
		selectColumn.setMinWidth(70);
		// selectColumn.setCellValueFactory(new PropertyValueFactory<User,
		// Boolean>("select"));

		Callback<TableColumn<User, Boolean>, TableCell<User, Boolean>> booleanCellFactory = new Callback<TableColumn<User, Boolean>, TableCell<User, Boolean>>() {
			@Override
			public TableCell<User, Boolean> call(TableColumn<User, Boolean> p) {
				return new BooleanCell();
			}
		};
		selectColumn.setCellValueFactory(new PropertyValueFactory<User, Boolean>("select"));
		selectColumn.setCellFactory(booleanCellFactory);
		selectColumn.setOnEditCommit(
				(CellEditEvent<User, Boolean> t) -> {
					((User) t.getTableView().getItems().get(
							t.getTablePosition().getRow())).setSelect(t.getNewValue());
				});

		TableColumn<User, String> nameColumn = new TableColumn<>("姓名");
		nameColumn.setMinWidth(100);
		nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));

		nameColumn.setCellFactory(forTextFieldTableColumn());
		nameColumn.setOnEditCommit(
				(CellEditEvent<User, String> t) -> {
					((User) t.getTableView().getItems().get(
							t.getTablePosition().getRow())).setName(t.getNewValue());
				});

		TableColumn<User, String> passwordColumn = new TableColumn<>("密码");
		passwordColumn.setMinWidth(100);
		passwordColumn.setCellValueFactory(new PropertyValueFactory<>("password"));
		passwordColumn.setCellFactory(forTextFieldTableColumn());
		passwordColumn.setOnEditCommit(
				(CellEditEvent<User, String> t) -> {
					((User) t.getTableView().getItems().get(
							t.getTablePosition().getRow())).setPassword(t.getNewValue());
				});

		TableColumn<User, String> emailColumn = new TableColumn<>("Email");
		emailColumn.setMinWidth(200);
		emailColumn.setCellValueFactory(new PropertyValueFactory<>("email"));
		emailColumn.setCellFactory(forTextFieldTableColumn());
		emailColumn.setOnEditCommit(
				(CellEditEvent<User, String> t) -> {
					((User) t.getTableView().getItems().get(
							t.getTablePosition().getRow())).setEmail(t.getNewValue());
				});

		table.setItems(dataList);
		table.getColumns().addAll(selectColumn, nameColumn, passwordColumn, emailColumn);

		final TextField nameTextField = new TextField();
		nameTextField.setPromptText("姓名");

		final TextField passwordTextField = new TextField();
		passwordTextField.setPromptText("密码");

		final TextField emailTextField = new TextField();
		emailTextField.setPromptText("Email");

		final Button addButton = new Button("Add");
		addButton.setOnAction((ActionEvent e) -> {
			int index = table.getSelectionModel().getSelectedIndex();

			User u = new User();
			u.setName(nameTextField.getText());
			u.setPassword(passwordTextField.getText());
			u.setEmail(emailTextField.getText());
			dataList.add(index + 1, u);
		});

		hb.getChildren().addAll(nameTextField, passwordTextField, emailTextField, addButton);
		hb.setSpacing(3);

		top.getChildren().addAll(showSelectButton, showDataButton);

		borderPane.setTop(top);
		borderPane.setCenter(table);
		borderPane.setBottom(hb);
	}

	private void iniEvent() {
		showSelectButton.setOnAction((ActionEvent e) -> {
			for (User u : dataList) {
				if (u.isSelect()) {
					System.out.println(u.getName());
				}
			}
		});

		showDataButton.setOnAction((ActionEvent e) -> {
			for (User u : dataList) {
				System.out.println(u.getName());
			}
		});
	}

	private void iniData() {
		User u = new User();
		u.setName("张1");
		u.setPassword("123456");
		u.setEmail("111111@qq.com");
		dataList.add(u);

		u = new User();
		u.setSelect(true);
		u.setName("张2");
		u.setPassword("123456");
		u.setEmail("222222@qq.com");
		dataList.add(u);

		u = new User();
		u.setName("张3");
		u.setPassword("123456");
		u.setEmail("333333@qq.com");
		dataList.add(u);

		u = new User();
		u.setName("张4");
		u.setPassword("123456");
		u.setEmail("444444@qq.com");
		dataList.add(u);

		u = new User();
		u.setName("张5");
		u.setPassword("123456");
		u.setEmail("555555@qq.com");
		dataList.add(u);

		u = new User();
		u.setName("张6");
		u.setPassword("123456");
		u.setEmail("666666@qq.com");
		dataList.add(u);

		u = new User();
		u.setName("张7");
		u.setPassword("123456");
		u.setEmail("777777@qq.com");
		dataList.add(u);

		// 第4行，第3列不可编辑
		addTableEdit(3, 2, false);
		// 第5行，第4列不可编辑
		addTableEdit(4, 3, false);
		// 第6行，第1列不可编辑
		addTableEdit(5, 0, false);
	}

	/**
	 * 设置多少行多少列可编辑
	 * 
	 * @param row
	 * @param column
	 * @param edit
	 */
	public void addTableEdit(int row, int column, boolean edit) {
		String key = row + "_" + column;
		map.put(key, edit);
	}

	public <S> Callback<TableColumn<S, String>, TableCell<S, String>> forTextFieldTableColumn() {
		return forTextFieldTableColumn(new DefaultStringConverter());
	}

	public <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> forTextFieldTableColumn(
			final StringConverter<T> converter) {
		return list -> new TextFieldTableCell<S, T>(converter) {
			public void startEdit() {
				// 判断当前行，当前列是否可编辑
				int row = this.getIndex();
				int column = table.getColumns().indexOf(this.getTableColumn());

				String key = row + "_" + column;
				if (map.containsKey(key)) {
					Boolean edit = map.get(key);
					if (null != edit && edit) {
						super.startEdit();
					}
				} else {
					super.startEdit();
				}
			}
		};
	}

	class BooleanCell extends TableCell<User, Boolean> {
		private CheckBox checkBox;

		public BooleanCell() {
			checkBox = new CheckBox();
			checkBox.setDisable(true);
			checkBox.selectedProperty().addListener(new ChangeListener<Boolean>() {
				public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
					if (isEditing()) {
						commitEdit(newValue == null ? false : newValue);
					}
				}
			});
			this.setGraphic(checkBox);
			// this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
			this.setEditable(true);
		}

		@Override
		public void startEdit() {
			// 判断当前行，当前列是否可编辑
			int row = this.getIndex();
			int column = table.getColumns().indexOf(this.getTableColumn());

			String key = row + "_" + column;
			if (map.containsKey(key)) {
				Boolean edit = map.get(key);
				if (null != edit && edit) {
					super.startEdit();
					if (isEmpty()) {
						return;
					}
					checkBox.setDisable(false);
					checkBox.requestFocus();
				}
			} else {
				super.startEdit();
				if (isEmpty()) {
					return;
				}
				checkBox.setDisable(false);
				checkBox.requestFocus();
			}
		}

		@Override
		public void cancelEdit() {
			super.cancelEdit();
			checkBox.setDisable(true);
		}

		public void commitEdit(Boolean value) {
			super.commitEdit(value);
			checkBox.setDisable(true);
		}

		@Override
		public void updateItem(Boolean item, boolean empty) {
			super.updateItem(item, empty);
			if (!isEmpty()) {
				checkBox.setSelected(item);
			}
		}
	}
}
